package com.example.shardingsphere.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.example.shardingsphere.common.config.UserContextHolder;
import com.example.shardingsphere.common.constant.Constants;
import com.example.shardingsphere.common.utils.JWTUtil;
import com.example.shardingsphere.common.utils.MD5Util;
import com.example.shardingsphere.common.utils.UUIDUtil;
import com.example.shardingsphere.controller.emums.UserIdentityEnum;
import com.example.shardingsphere.controller.param.UserLoginParam;
import com.example.shardingsphere.controller.param.UserParam;
import com.example.shardingsphere.controller.param.UserPasswordLoginParam;
import com.example.shardingsphere.controller.result.TableDataInfo;
import com.example.shardingsphere.controller.result.UserLoginResult;
import com.example.shardingsphere.entity.OperationLogs;
import com.example.shardingsphere.entity.User;
import com.example.shardingsphere.fegin.ProductFeginClient;
import com.example.shardingsphere.repository.UserRepository;
import com.example.shardingsphere.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
public class UserServiceImpl implements UserService {
    private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    private final Snowflake snowflakeIdGenerator;

    @Autowired
    public UserServiceImpl(Snowflake snowflakeIdGenerator) {
        this.snowflakeIdGenerator = snowflakeIdGenerator;
    }

    @Autowired
    private UserRepository userRepository;
    @Resource
    private ProductFeginClient productFeginClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 查询用户信息
     * 普通用户仅自己，管理员所有普通用户，超管全部
     * userId 任意用户ID
     */
    @Override
    public User getUserById(Long userId) {
        //根据上下文拿到用户角色
        UserContextHolder.UserInfo userInfo = UserContextHolder.getUser();
        //检查用户的权限
        if (!hasPermission(userInfo, userId)) {
            throw new RuntimeException("无权限访问");
        }
        return userRepository.selectById(userId);
    }

    private boolean hasPermission(UserContextHolder.UserInfo userInfo, Long userId) {
        if (userInfo == null) {
            return false;
        }
        String role_code = userInfo.getRole();
        //超级管理员
        if (UserIdentityEnum.SUPER_ADMIN.getMassage().equals(role_code)) {
            return true;
        }
        //管理员 访问普通用户
        if (UserIdentityEnum.ADMIN.getMassage().equals(role_code)) {
            String userRoleCode = productFeginClient.getUserRoleCode(userId);
            return UserIdentityEnum.NORMAL.getMassage().equals(userRoleCode);
        }

        //普通用户访问自己
        if (UserIdentityEnum.NORMAL.getMassage().equals(role_code)) {
            return userInfo.getUserId().equals(userId);
        }

        return false;
    }

    @Override
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)

    public Integer register(User user) {
        // 参数校验
        if (user == null) {
            throw new IllegalArgumentException("用户参数为空！");
        }
        //查询当前用户是否存在  exist 存在
        User existUser = userRepository.selectUserName(user.getUsername());
        if (null != existUser) {
            logger.info("用户已存在！");
            throw new IllegalArgumentException("用户已存在！");
        }
        User existPhoneUser = userRepository.selectUsersByPhone(user.getPhone());
        if (null != existPhoneUser) {
            logger.info("手机号已存在！");
            throw new IllegalArgumentException("手机号已存在！");
        }
        User existEmailUser = userRepository.selectUsersByEmail(user.getEmail());
        if (null != existEmailUser) {
            logger.info("邮箱已存在！");
            throw new IllegalArgumentException("邮箱已存在！");
        }
        // 设置用户信息
        Long userId = snowflakeIdGenerator.nextId();
        user.setUserId(userId);
        user.setGmtCreate(new Date());
        // 生成唯一盐值
        String salt = UUIDUtil.UUID_32();
        // 使用盐值加密密码
        String encryptedPassword = MD5Util.md5Salt(user.getPassword(), salt);
        user.setPassword(encryptedPassword);
        user.setSalt(salt);

        // 1. 分库分表写入用户表
        Integer result = userRepository.insert(user);
        if (result <= 0) {
            throw new RuntimeException("Failed to insert user");
        }

        // 2. RPC调用绑定默认角色，确保传递正确的userId
        Integer i = productFeginClient.bindDefaultRole(userId);
        if (i <= 0) {
            throw new RuntimeException("Failed to bind default role");
        }

        //3.发送日志消息至MQ
        try {
            OperationLogs logs = new OperationLogs();
            logs.setUserId(userId);
            logs.setAction("user_register");
            logs.setIp("127.0.0.1");
            logs.setDetail("用户注册成功");
            //利用 mq 发送消息(对象) 需要json 处理
            rabbitTemplate.convertAndSend(Constants.DIRECT_SHUZIMALI_EXCHANGE, "shuzimali", logs);
        } catch (Exception e) {
            // 记录错误日志，但不影响主业务流程
            logger.error("Failed to send operation log to MQ", e);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserLoginResult login(UserLoginParam param) throws Exception {
        if (param instanceof UserPasswordLoginParam) {
            return passwordLogin((UserPasswordLoginParam) param);
        } else {
            throw new IllegalArgumentException("不支持的登录方式");
        }
    }

    /**
     * 密码登录
     *
     * @param param
     * @return
     */
    private UserLoginResult passwordLogin(UserPasswordLoginParam param) {
        String loginName = param.getLoginName();
        logger.info("登录名（）：{}", loginName);
        String password = param.getPassword();
        logger.info("密码：{}", password);
        //查询用户 根据手机号或者邮箱
        User user = userRepository.findByEmailOrPhone(loginName);
        logger.info("用户：{}", user);
        String encryptPassword = MD5Util.md5Salt(password, user.getSalt());
        logger.info("加密后的密码：{}", encryptPassword);
        if (user == null || !user.getPassword().equals(encryptPassword)) {
            throw new IllegalArgumentException("用户名或密码错误！");
        }
        //远程调用获取用户角色码
        String userRoleCode = productFeginClient.getUserRoleCode(user.getUserId());
        logger.info("用户角色码：{}", userRoleCode);
        if (userRoleCode == null) {
            throw new IllegalArgumentException("用户角色不存在！");
        }
        // 3. 生成 JWT Token（示例）
        Map<String, Object> claim = new HashMap<>();
        claim.put("userId", user.getUserId());
        claim.put("role_code", userRoleCode);
        String token = JWTUtil.genJwt(claim);
        return new UserLoginResult(token, userRoleCode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TableDataInfo<User> getUserList(int pageNum, int pageSize) {
        TableDataInfo<User> tableDataInfo = null;
        //从用户上下文中获取当前用户信息
        UserContextHolder.UserInfo userInfo = UserContextHolder.getUser();
        if (userInfo == null) {
            return TableDataInfo.error("1000", "用户未授权！");
        }
        String role = userInfo.getRole();

        if (UserIdentityEnum.SUPER_ADMIN.getMassage().equals(role)) {
            //超管，查询所有用户
            Long total = userRepository.countAllUsers();
            List<User> userList = userRepository.selectAllUsers(pageNum, pageSize);
            tableDataInfo = new TableDataInfo<>(userList, total, pageNum, pageSize);
        } else if (UserIdentityEnum.ADMIN.getMassage().equals(role)) {
            //管理员，显示所有正常用户列表
            List<Long> normalUserIds = productFeginClient.getNormalUserIds();
            Long total = (long) normalUserIds.size();
            List<User> userList = userRepository.selectUsersByIds(normalUserIds,pageNum, pageSize);
            tableDataInfo = new TableDataInfo<>(userList, total, pageNum, pageSize);
        } else {
            // 普通用户，仅查自己
            List<User> userList = new ArrayList<>();
            userList.add(userRepository.selectById(UserContextHolder.getCurrentUserId()));
            tableDataInfo = new TableDataInfo<>(userList, 1L, pageNum, pageSize);
        }
        return tableDataInfo;
    }

    @Override
    public Boolean canUpdateUser(Long userId, UserParam userParam) {
        //根据上下文拿到用户角色
        UserContextHolder.UserInfo userInfo = UserContextHolder.getUser();
        //检查用户的权限
        if (!updateUser(userInfo, userId)) {
            throw new RuntimeException("无权限访问");
        }
        //前端会调用查询方法显示,然后再修改提交
        //User user = userRepository.selectById(userId);

        // 2. 数据合法性校验
        if (StringUtils.isBlank(userParam.getUsername())) {
            throw  new IllegalArgumentException("用户名不能为空");
        }

        // 3. 执行修改
        User targetUser = userRepository.selectById(userId);
        targetUser.setUserId(userId);
        // 只更新需要修改的字段
        if (StringUtils.isNotBlank(userParam.getUsername())) {
            targetUser.setUsername(userParam.getUsername());
        }
        if (StringUtils.isNotBlank(userParam.getPassword())) {
            String salt = UUIDUtil.UUID_32();
            String newPassword = MD5Util.md5Salt(userParam.getPassword(), salt);
            targetUser.setPassword(newPassword);
            targetUser.setSalt(salt);
        }
        if (StringUtils.isNotBlank(userParam.getPhone())) {
            targetUser.setPhone(userParam.getPhone());
        }
        if (StringUtils.isNotBlank(userParam.getEmail())) {
            targetUser.setEmail(userParam.getEmail());
        }
        Integer result = userRepository.updateUser(targetUser);
        return result == 1 ? true : false;
    }


    private boolean updateUser(UserContextHolder.UserInfo userInfo, Long userId) {
        if (userInfo == null) {
            return false;
        }
        String role_code = userInfo.getRole();
        //超级管理员
        if (UserIdentityEnum.SUPER_ADMIN.getMassage().equals(role_code)) {
            return true;
        }
        //管理员操作普通用户
        if (UserIdentityEnum.ADMIN.getMassage().equals(role_code)) {
            String userRoleCode = productFeginClient.getUserRoleCode(userId);
            return UserIdentityEnum.NORMAL.getMassage().equals(userRoleCode);
        }

        //普通用户操作自己
        if (UserIdentityEnum.NORMAL.getMassage().equals(role_code)) {
            return userInfo.getUserId().equals(userId);
        }

        return false;
    }


    /**
     * 修改密码
     *
     * @param userId 目标用户ID
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @return
     */
    @Override
    public Boolean resetPassword(Long userId, String oldPassword, String newPassword) {
        //根据上下文拿到用户角色
        UserContextHolder.UserInfo userInfo = UserContextHolder.getUser();
        logger.info("用户角色：{}", userInfo.getRole());
        //检查用户的权限
        if (!updateUser(userInfo, userId)) {
            throw new RuntimeException("无权限访问");
        }

        //检查用户旧密码是否正确
        //拿到对应用户的数据库信息
        User user = userRepository.select(userId);
        logger.info("user:" +  user);
        logger.info("用户旧密码：{}", oldPassword);
        logger.info("数据库盐：{}", user.getSalt());
        logger.info("用户旧密码数据库加密：{}", user.getPassword());
        String oldSaltPassword = MD5Util.md5Salt(oldPassword, user.getSalt());
        logger.info("用户旧密码md5重新加密：{}", oldSaltPassword);
        if (!oldSaltPassword.equals(user.getPassword())) {
            throw new RuntimeException("旧密码错误");
        }
        String salt = UUIDUtil.UUID_32();
        String newSeltPassword = MD5Util.md5Salt(newPassword, salt);
        user.setPassword(newSeltPassword);
        user.setSalt(salt);
        user.setUserId(userId);
        Integer result = userRepository.updateUser(user);
        return result == 1 ? true : false;
    }
}